home *** CD-ROM | disk | FTP | other *** search
/ JCSM Shareware Collection 1996 September / JCSM Shareware Collection (JCS Distribution) (September 1996).ISO / prgtools / euphor13.zip / SEARCH.EX < prev    next >
Text File  |  1995-06-14  |  11KB  |  443 lines

  1. -- This program searches for a string in files of the current directory 
  2. -- and subdirectories.
  3. -- usage:  
  4. --      search [string] 
  5. --
  6. -- If you don't supply a string on the command line you will be prompted 
  7. -- for it. The string may contain * and ? wildcard characters and so may 
  8. -- the list of file specifications. Lines containing the string are 
  9. -- displayed on the screen, and also recorded in C:\SEARCH.OUT. 
  10. -- Some statistics are printed at the end.
  11. -- Example:
  12. --
  13. --   C:\> search
  14. --   string: p?oc*re
  15. --   match case? (y)
  16. --   file-spec (*.*): *.e *.ex
  17. --   scan subdirectories? (y)
  18. --
  19. -- Note: if you just hit Enter instead of supplying a string to search for,
  20. -- the program will simply print any file names that match your file-spec.
  21.  
  22. -------- some user-modifiable parameters: 
  23.  
  24. sequence log_name, log_path
  25. log_name = "search.out"
  26. log_path = "c:\\" & log_name  -- place to store results
  27.  
  28. -- when you search "*.*" the following files 
  29. -- will actually be skipped (to save time):
  30. sequence skip_list 
  31. skip_list = {
  32.     "*.EXE", "*.ZIP", "*.BMP", "*.GIF",
  33.     "*.DLL", "*.OBJ" 
  34. }
  35.  
  36. -------- end of user-modifiable parameters 
  37.  
  38. without type_check
  39.  
  40. include file.e
  41. include wildcard.e
  42. include sort.e
  43. include graphics.e
  44.  
  45. constant KEYB = 0, SCREEN = 1, ERR = 2
  46.  
  47. constant TRUE = 1, FALSE = 0
  48. constant EOF = -1
  49.  
  50. type boolean(integer x)
  51.     return x = 0 or x = 1
  52. end type
  53.  
  54. sequence pos, cmd, string, orig_string, file_spec
  55.  
  56. boolean match_case, scan_subdirs, wild_string, wait
  57.  
  58. integer line_count
  59.  
  60. integer scanned, skipped, no_open, total_found
  61. scanned = 0
  62. skipped = 0
  63. no_open = 0
  64. total_found = 0
  65.  
  66. atom start_time
  67. integer log_file
  68.  
  69. log_file = open(log_path, "w")
  70. if log_file = -1 then
  71.     puts(ERR, "Couldn't open " & log_path & '\n')
  72.     abort(1)
  73. end if
  74.  
  75. function alphabetic(object s)
  76. -- does s contain alphabetic characters?
  77.     return find(TRUE, (s >= 'A' and s <= 'Z') or
  78.               (s >= 'a' and s <= 'z')) 
  79. end function
  80.  
  81. constant LINE_WIDTH = 80
  82.  
  83. function clean(sequence line)
  84. -- replace any funny control characters 
  85. -- and put in \n's to help break up long lines
  86.     sequence new_line
  87.     integer c, col
  88.     
  89.     new_line = ""
  90.     col = 1
  91.     for i = 1 to length(line) do
  92.     if col > LINE_WIDTH then
  93.         new_line = append(new_line, '\n')
  94.         col = 1
  95.     end if
  96.     c = line[i]
  97.     col = col + 1
  98.     if c < 32 then
  99.         if c = '\t' or c = '\r' then
  100.         c = ' '
  101.         elsif c = '\n' then
  102.         col = 1
  103.         else    
  104.         c = '.'
  105.         end if
  106.     end if
  107.     new_line = append(new_line, c)
  108.     end for
  109.     return new_line
  110. end function
  111.  
  112. procedure both_puts(object text)
  113.     puts(SCREEN, text)
  114.     puts(log_file, text)
  115. end procedure
  116.  
  117. procedure both_printf(sequence format, object values)
  118.     printf(SCREEN, format, values)
  119.     printf(log_file, format, values)
  120. end procedure
  121.  
  122. function plural(integer n)
  123. -- Yes, this is a bit obsessive...
  124.     if n = 1 then
  125.     return ""
  126.     else
  127.     return "s"
  128.     end if
  129. end function
  130.  
  131. procedure list_file_spec()
  132.     for i = 1 to length(file_spec) do
  133.     both_puts(file_spec[i])
  134.     if i != length(file_spec) then
  135.         both_puts(" ")
  136.     end if
  137.     end for
  138. end procedure
  139.  
  140. procedure final_stats()
  141. -- show final statistics    
  142.  
  143.     puts(SCREEN, repeat(' ', 80))
  144.     if length(string) = 0 then
  145.     both_printf("%d file name" & plural(total_found) & " matched (", 
  146.              total_found)
  147.     list_file_spec()
  148.     both_puts(")\n")
  149.     both_printf("%d names did not match\n", skipped)
  150.     else
  151.     both_printf("\n%5d file" & plural(scanned) & " scanned (", scanned)
  152.     list_file_spec()
  153.     both_printf(")\n%5d file" & plural(skipped) & " skipped\n", skipped)
  154.     both_printf("%5d file" & plural(total_found) & 
  155.             " contained \"%s\" ", {total_found, orig_string})
  156.     if alphabetic(orig_string) then
  157.         if match_case then
  158.         both_puts("(case must match)")
  159.         else
  160.         both_puts("(any case)")
  161.         end if
  162.     end if
  163.     both_puts('\n')
  164.     if no_open then
  165.         both_printf("couldn't open %d file" & plural(no_open) & '\n', 
  166.              no_open)
  167.     end if
  168.     end if
  169.     printf(SCREEN, "search time: %.1f seconds\n", time()-start_time)
  170.     if total_found then
  171.     puts(SCREEN, "\nSee " & log_path & '\n')
  172.     end if
  173.     close(log_file)
  174.     if wait then
  175.     puts(SCREEN, "Enter to continue ...\n")
  176.     if getc(KEYB) then
  177.     end if
  178.     end if
  179. end procedure
  180.  
  181. constant MAX_LINE = 1000 
  182.              
  183. function safe_gets(integer fn)
  184. -- Return the next line of text.
  185. -- Lines are split at MAX_LINE to prevent
  186. -- "out of memory" problems on humongous lines
  187. -- and to reduce the amount of extraneous output.
  188.     sequence line
  189.     integer c
  190.     
  191.     line = ""
  192.     for i = 1 to MAX_LINE do
  193.     c = getc(fn)
  194.     if c <= '\n' then
  195.         if c = '\n' then
  196.         return line & c
  197.         elsif c = EOF then
  198.         if i = 1 then
  199.             return EOF
  200.         else
  201.             exit
  202.         end if
  203.         end if
  204.     end if
  205.     line = line & c
  206.     end for
  207.     return line & '\n'
  208. end function
  209.  
  210. constant SAFE_FILE_SIZE = 100000
  211.  
  212. function scan(sequence file_name, integer file_size, sequence string)
  213. -- print all lines in current file containing the string
  214.     object line
  215.     sequence match_line
  216.     integer fileNum
  217.     boolean found, found_in_file
  218.     
  219.     if length(string) = 0 then
  220.     -- just looking for file names
  221.     both_puts(file_name & ":\n")
  222.     return 1
  223.     end if
  224.     fileNum = open(file_name, "rb")   
  225.     if fileNum = -1 then
  226.     no_open = no_open + 1
  227.     return 0
  228.     end if
  229.     found_in_file = FALSE
  230.     wrap(FALSE)
  231.     puts(SCREEN, file_name & ':' & repeat(' ', 80) & '\r')
  232.     wrap(TRUE)
  233.     while TRUE do
  234.     if file_size > SAFE_FILE_SIZE then
  235.         line = safe_gets(fileNum)
  236.     else
  237.         line = gets(fileNum)    
  238.     end if
  239.     if atom(line) then
  240.         exit -- end of file
  241.     else
  242.         if match_case then
  243.         match_line = line
  244.         else
  245.         match_line = lower(line)
  246.         end if
  247.         if wild_string then
  248.         found = wildcard_match(string, match_line) 
  249.         else        
  250.         found = match(string, match_line) 
  251.         end if
  252.         if found then
  253.         both_puts(clean(file_name & ": " & line))
  254.         found_in_file = TRUE
  255.         end if
  256.     end if
  257.     end while
  258.     
  259.     scanned = scanned + 1
  260.     close(fileNum)
  261.     return found_in_file
  262. end function
  263.  
  264. procedure look_at(sequence path_name, sequence entry)
  265. -- see if a file name qualifies for searching
  266.     boolean matched_one
  267.     sequence file_name
  268.     
  269.     file_name = entry[D_NAME]
  270.     if compare(file_name, log_name) = 0 then
  271.     return -- avoid circularity
  272.     end if
  273.     if compare(file_spec[1], "*.*") = 0 then
  274.     -- check skip list
  275.     for i = 1 to length(skip_list) do
  276.         if wildcard_file(skip_list[i], file_name) then
  277.         skipped = skipped + 1
  278.         return
  279.         end if
  280.     end for
  281.     else
  282.     -- go through list of file specs
  283.     matched_one = FALSE
  284.     for i = 1 to length(file_spec) do
  285.         if wildcard_file(file_spec[i], file_name) then
  286.         matched_one = TRUE
  287.         exit
  288.         end if
  289.     end for
  290.     if not matched_one then
  291.         skipped = skipped + 1
  292.         return
  293.     end if
  294.     end if
  295.     path_name = path_name & '\\'
  296.     if compare(path_name[1..2], ".\\") = 0 then
  297.     path_name = path_name[3..length(path_name)]
  298.     end if
  299.     path_name = path_name & file_name
  300.     total_found = total_found + scan(path_name, entry[D_SIZE], string)
  301. end procedure
  302.  
  303. procedure walk_dir(sequence path_name)
  304. -- walk through a directory and its subdirectories 
  305. -- in alphabetical order, "looking" at each file
  306.     object d
  307.     integer key
  308.     
  309.     d = dir(path_name)
  310.     while find(path_name[length(path_name)], " \\") do
  311.     path_name = path_name[1..length(path_name)-1]
  312.     end while
  313.     if atom(d) then
  314.     puts(ERR, "\nCouldn't access " & path_name & '\n')
  315.     return
  316.     end if
  317.     d = sort(d) -- sort-by-name (first field of d)
  318.     for i = 1 to length(d) do
  319.     if find('d', d[i][D_ATTRIBUTES]) then
  320.         if not find(d[i][D_NAME], {".", ".."}) then
  321.         if scan_subdirs then
  322.             walk_dir(path_name & '\\' & d[i][D_NAME])
  323.         end if
  324.         end if
  325.     else
  326.         look_at(path_name, d[i])
  327.     end if
  328.     key = get_key()
  329.     if key = 'q' then
  330.         final_stats()
  331.         abort(1)
  332.     end if
  333.     end for
  334. end procedure
  335.  
  336. function blank_delim(sequence s)
  337. -- break up a blank-delimited string
  338.     sequence list, segment
  339.     integer i
  340.     list = {}
  341.     i = 1
  342.     while i < length(s) do
  343.     while find(s[i], " \t") do
  344.         i = i + 1
  345.     end while
  346.     if s[i] = '\n' then
  347.         exit
  348.     end if
  349.     segment = ""
  350.     while not find(s[i], " \t\n") do
  351.         segment = segment & s[i]
  352.         i = i + 1
  353.     end while
  354.     list = append(list, segment)
  355.     end while
  356.     return list
  357. end function
  358.  
  359. procedure get_file_spec()
  360. -- read in a list of file specifications from user
  361. -- result is stored in file_spec sequence of strings
  362.     sequence spec
  363.     
  364.     puts(SCREEN, "file-spec (*.*): ")
  365.     spec = gets(KEYB)
  366.     puts(SCREEN, '\n')
  367.     file_spec = blank_delim(spec)
  368.     if length(file_spec) = 0 then
  369.     file_spec = {"*.*"}
  370.     end if
  371. end procedure
  372.  
  373. log_name = upper(log_name)
  374.  
  375. cmd = command_line()            -- ex search.ex [string]
  376. wait = match("SEARCH", cmd[2])  -- wait at end (running in FILE|RUN window)
  377.  
  378. if length(cmd) >= 3 then
  379.     orig_string = cmd[3]
  380. else
  381.     puts(SCREEN, "string:")
  382.     orig_string = gets(KEYB)
  383.     orig_string = orig_string[1..length(orig_string)-1] -- remove \n
  384.     puts(SCREEN, '\n')
  385. end if
  386.  
  387. if alphabetic(orig_string) then
  388.     puts(SCREEN, "match case? (y)")
  389.     pos = get_position()
  390.     position(pos[1], pos[2] - 2)
  391.     match_case = not match("n", gets(KEYB))
  392.     puts(SCREEN, '\n')
  393. else
  394.     match_case = TRUE   
  395. end if
  396.  
  397. string = orig_string
  398. if not match_case then
  399.     string = lower(string)
  400. end if
  401.  
  402. wild_string = find('?', string) or find('*', string) 
  403. if wild_string then
  404.     string = '*' & string & '*' -- too match whole line
  405. end if
  406.  
  407. get_file_spec()
  408.  
  409. -- avoid asking about subdirectories 
  410. -- when there aren't any...
  411. object d
  412. d = dir(current_dir())
  413. if atom(d) then
  414.     puts(SCREEN, "network drive not available\n")
  415.     abort(1)
  416. end if
  417. for i = 1 to length(d) do
  418.     if find('d', d[i][D_ATTRIBUTES]) then
  419.     if not find(d[i][D_NAME], {".", ".."}) then
  420.         puts(SCREEN, "scan subdirectories? (y)")
  421.         pos = get_position()
  422.         position(pos[1], pos[2] - 2)
  423.         scan_subdirs = not match("n", gets(KEYB))
  424.         exit
  425.     end if          
  426.     end if
  427. end for
  428.  
  429. puts(SCREEN, "\npress q to quit\n\n")
  430.  
  431. start_time = time()
  432. if sequence(dir(".")) then
  433.     puts(log_file, "Searching " & current_dir() & "\n\n")
  434.     walk_dir(".")
  435. else
  436.     walk_dir(current_dir())
  437. end if
  438.  
  439. final_stats()
  440.  
  441. without warning
  442.  
  443.